package com.xbongbong.paas.script.distributor.controller;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.pojo.dto.FixDataJobDTO;
import com.xbongbong.paas.script.pojo.dto.DistributorProductDataDTO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.config.ProBaseConfig;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.constant.XbbProConstant;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.model.ProductModel;
import com.xbongbong.saas.script.help.InitExplainsHelper;
import com.xbongbong.saas.script.tempenum.TempProductEnum;
import com.xbongbong.sys.model.CompanyModel;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.MinAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.MediaType;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * 经销商上线 产品解释、数据表
 * @author feng.zheng
 * @version v1.0
 * @date 2020/12/21 08:55
 * @since v1.0
 */
@RestController
@RequestMapping(XbbProConstant.API_ROOT_PREFIX + "/script/distributor/product")
public class DistributorProductDataScriptController {
    private static final Logger LOG = LoggerFactory.getLogger(DistributorProductDataScriptController.class);

    @Resource
    private ProBaseConfig proBaseConfig;
    @Resource
    private ProductModel productModel;
    @Resource
    private CompanyModel companyModel;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;


    @RequestMapping(value = "/addProductExplain", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String addProductExplain(@RequestBody @Valid FixDataJobDTO fixDataJobDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(fixDataJobDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006, SystemErrorCodeEnum.API_ERROR_100006.getMsg());
        }
        long start = DateTimeUtil.getInt();
        LocaleContextHolder.setLocale(Locale.CHINA);
        List<String> corpidList = fixDataJobDTO.getCorpidList();
        if (CollectionsUtil.isEmpty(corpidList)) {
            corpidList = companyModel.getCorpidList();
        }
        List<String> exclude = fixDataJobDTO.getExclude();
        if (CollectionsUtil.isNotEmpty(exclude)) {
            corpidList.removeAll(exclude);
        }
        LOG.warn("数据库中共有公司" + corpidList.size() + "家");
        int corpidCount = 0;

        List<FieldAttrEntity> fieldAttrList = new ArrayList<>();
        List<String> enumAttrs = InitExplainsHelper.getBusinessEnumAttrs(ProductEnum.class);
        List objs = Arrays.asList(ProductEnum.ONLINE_TIME, ProductEnum.SALES);

        for (Object obj : objs) {
            FieldAttrEntity newFieldAttrEntity = InitExplainsHelper.setField(ProductEnum.class, enumAttrs, obj);
            try {
                Method method = TempProductEnum.class.getMethod("init" + newFieldAttrEntity.getSaasAttr().substring(0, 1).toUpperCase() + newFieldAttrEntity.getSaasAttr().substring(1), FieldAttrEntity.class);
                method.invoke(TempProductEnum.class, newFieldAttrEntity);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
            newFieldAttrEntity.setIsRedundant(0);
            fieldAttrList.add(newFieldAttrEntity);
        }

        Set<String> attrList = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (FieldAttrEntity fieldAttrEntity : fieldAttrList) {
            attrList.add(fieldAttrEntity.getAttr());
        }
        for (String corpid : corpidList) {
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
            param.put(ParameterConstant.CORPID, corpid);
            param.put("businessType", XbbRefTypeEnum.PRODUCT.getCode());
            List<PaasFormExplainEntity> entitys = paasFormExplainModel.getNoHandleExplainsByFindEntitys(param);
            for (PaasFormExplainEntity entity : entitys){
                if (Objects.equals("[]", entity.getExplains())) {
                    continue;
                }
                boolean canInsert = true;
                List<FieldAttrEntity> fieldAttrEntityList = JSONArray.parseArray(entity.getExplains(),FieldAttrEntity.class);

                int obj = 0;
                for(int i = 0; i < fieldAttrEntityList.size(); i++){

                    FieldAttrEntity fieldAttrEntity = fieldAttrEntityList.get(i);
                    //插入到当前字段后面
                    if (Objects.equals(fieldAttrEntity.getAttr(), ProductEnum.UPDATE_TIME.getAttr())) {
                        obj = i + 1 ;
                    }
                    if (attrList.contains(fieldAttrEntity.getAttr())) {
                        canInsert = false;
                        LOG.warn(corpid + "该公司已经存在" + fieldAttrEntity.getAttr() + "字段");
                        break;
                    }
                }
                if (canInsert && obj != 0) {
                    for (int i = 0; i < fieldAttrList.size(); i++) {
                        FieldAttrEntity fieldAttrEntity = fieldAttrList.get(i);
                        fieldAttrEntityList.add(obj + i , fieldAttrEntity);
                    }
                    String explains = JSONObject.toJSONString(fieldAttrEntityList);
                    entity.setExplains(explains);
                    paasFormExplainModel.update(entity);
                }else {
                    String explains = JSONObject.toJSONString(fieldAttrEntityList);
                    entity.setExplains(explains);
                    paasFormExplainModel.update(entity);
                }
            }
            ++ corpidCount;
            LOG.warn("公司" + corpidCount + "/" + corpidList.size() + "/" +corpid);
        }

        LOG.warn("consume:" + (DateTimeUtil.getInt() - start));
        LOG.warn("操作成功");
        return "success";
    }

    @RequestMapping(value = "/generateProductData", method = RequestMethod.POST)
    public String generateProductData(@RequestBody @Valid DistributorProductDataDTO productDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(productDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }
        long start = DateTimeUtil.getInt();
        List<String> corpidList = productDTO.getCorpidList();
        if (CollectionsUtil.isEmpty(corpidList)) {
            corpidList = productModel.getCorpidList();
        }
        List<String> exclude = productDTO.getExclude();
        if (CollectionsUtil.isNotEmpty(exclude)) {
            corpidList.removeAll(exclude);
        }
        LOG.info("数据库中共有公司" + corpidList.size() + "家");
        int corpidCount = 0;
        SearchRequest searchRequest;
        SearchSourceBuilder sourceBuilder;
        BoolQueryBuilder boolQueryBuilder;
        BoolQueryBuilder childBoolQueryBuilder;
        List<PaasFormDataEntity> content;

        String[] fieldList = new String[]{StringConstant.SAAS_LINK_BUSINESS_ID, ProductEnum.getAttrConnectData(ProductEnum.PRICE), ProductEnum.getAttrConnectData(ProductEnum.PARENT_ID),FieldTypeEnum.ADDTIME.getAlias(),FieldTypeEnum.UPDATETIME.getAlias(), ProductEnum.getAttrConnectData(ProductEnum.ONLINE),ProductEnum.getAttrConnectData(ProductEnum.ONLINE_TIME)};
        for (String corpid : corpidList) {
            searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_PRODUCT.getIndex());
            sourceBuilder = new SearchSourceBuilder();
            boolQueryBuilder = boolQuery();
            boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
            boolQueryBuilder.filter(termQuery(ParameterConstant.DEL, DelEnum.NORMAL.getDel()));
            boolQueryBuilder.filter(termQuery(ProductEnum.getAttrConnectData(ProductEnum.PARENT_ID), 0));
            boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,IndexTypeEnum.IDX_SAAS_PRODUCT.getType()));
            if (Objects.nonNull(productDTO.getUpdateTimeStart())) {
                boolQueryBuilder.filter(rangeQuery(FieldTypeEnum.UPDATETIME.getAlias()).gte(productDTO.getUpdateTimeStart()));
            }
            sourceBuilder.query(boolQueryBuilder);
            sourceBuilder.sort(new FieldSortBuilder(StringConstant.SAAS_LINK_BUSINESS_ID).order(SortOrder.ASC));
            sourceBuilder.fetchSource(fieldList, null);
            //分页
            sourceBuilder.from(0);
            sourceBuilder.size(1000);
            searchRequest.source(sourceBuilder);
            boolean addFlag = true;
            while (addFlag) {
                content = xbbElasticsearchRestTemplate.queryForList(searchRequest, PaasFormDataEntity.class);
                if (Objects.isNull(content) || content.isEmpty()) {
                    addFlag = false;
                } else {
                    LOG.warn("遍历id到" + content.get(content.size() - 1).getId());
                    sourceBuilder.searchAfter(new Object[]{content.get(content.size() -1).getId()});
                    List<Long> parentIdIn = new ArrayList<>();
                    content.forEach(entity ->parentIdIn.add(entity.getId()));
                    if (parentIdIn.isEmpty()) {
                        continue;
                    }
                    childBoolQueryBuilder = boolQuery();
                    childBoolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
                    childBoolQueryBuilder.filter(termQuery(ParameterConstant.DEL, DelEnum.NORMAL.getDel()));
                    childBoolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,IndexTypeEnum.IDX_SAAS_PRODUCT.getType()));
                    childBoolQueryBuilder.filter(termsQuery(ProductEnum.getAttrConnectData(ProductEnum.PARENT_ID), parentIdIn));
                    SearchSourceBuilder childSourceBuilder = new SearchSourceBuilder();
                    childSourceBuilder.query(childBoolQueryBuilder);
                    childSourceBuilder.size(0);
                    TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("parentId").field(ProductEnum.getAttrConnectData(ProductEnum.PARENT_ID)).size(parentIdIn.size());
                    MinAggregationBuilder minAggregationBuilder = AggregationBuilders.min("price").field(ProductEnum.getAttrConnectData(ProductEnum.PRICE));
                    termsAggregationBuilder.subAggregation(minAggregationBuilder);
                    childSourceBuilder.aggregation(termsAggregationBuilder);
                    SearchRequest childSearchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_PRODUCT.getIndex());
                    childSearchRequest.source(childSourceBuilder);
                    JSONObject aggJson = xbbElasticsearchRestTemplate.getAggResponseJson(childSearchRequest);
                    JSONArray bucketsArr = aggJson.getJSONObject("aggregations").getJSONObject("parentId").getJSONArray("buckets");
                    Map<Long, Double> priceMap = new HashMap<>();
                    for (int i = 0; i < bucketsArr.size(); i ++) {
                        JSONObject jsonObject = bucketsArr.getJSONObject(i);
                        priceMap.put(jsonObject.getLong("key"), jsonObject.getJSONObject("price").getDoubleValue("value"));
                    }
                    List<UpdateDataEntity> updateList = new ArrayList<>();
                    JSONObject updateData;
                    for (PaasFormDataEntity paasFormDataEntity :  content) {
                        updateData = new JSONObject();
                        if (priceMap.containsKey(paasFormDataEntity.getId())) {
                            updateData.put(ProductEnum.PRICE.getAttr(), priceMap.get(paasFormDataEntity.getId()));
                        }
                        updateData.put(ProductEnum.SALES.getAttr(), 0);
                        if (Objects.equals(paasFormDataEntity.getData().getInteger(ProductEnum.ONLINE.getAttr()), 1) && Objects.isNull(paasFormDataEntity.getData().get(ProductEnum.ONLINE_TIME.getAttr()))) {
                            updateData.put(ProductEnum.ONLINE_TIME.getAttr(), paasFormDataEntity.getAddTime());
                        }
                        updateList.add(ExplainUtil.getUpdateData(paasFormDataEntity.getId(), updateData, corpid, paasFormDataEntity.getUpdateTime()));
                    }
                    productModel.updateBatch4JobNoEs(updateList, corpid);
                }
            }
            corpidCount ++;
            LOG.info("公司" + corpidCount + "/" + corpidList.size());
        }
        LOG.info("time:" + (DateTimeUtil.getInt() - start));
        LOG.info("---------------- over----------");
        return "success";
    }
}
